package de.jonasblatt.networkapi.rpi.model.gpio;

import java.util.HashMap;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalInput;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.Pin;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;

public class GpioWorker {
	private GpioController gpioRactory;
	private HashMap<String, GpioPinDigitalOutput> gpiosOut;
	private HashMap<String, GpioPinDigitalInput> gpiosIn;

	public GpioWorker() {
		this.gpioRactory = GpioFactory.getInstance();
		this.gpiosOut = new HashMap<>();
		this.gpiosIn = new HashMap<>();
	}

	public void setGpioOff(String gpio) {
		GpioPinDigitalOutput gpioout = null;
		try {
			gpioout = this.getGpioOutput(gpio);
		} catch (Exception e) {
		}
		if (gpioout != null) {
			gpioout.low();
		}
	}

	public void setGpioOn(String gpio) {
		GpioPinDigitalOutput gpioout = null;
		try {
			gpioout = this.getGpioOutput(gpio);
		} catch (Exception e) {
		}
		if (gpioout != null) {
			gpioout.high();
		}
	}

	public boolean getGpioValue(String gpio) {
		GpioPinDigitalInput gpioin = null;
		try {
			gpioin = this.getGpioInput(gpio);
		} catch (Exception e) {
		}
		if (gpioin == null) {
			return false;
		} else {
			return gpioin.isHigh();
		}
	}

	private GpioPinDigitalInput getGpioInput(String gpio) throws Exception {
		if (this.gpiosOut.containsKey(gpio)) {
			throw new Exception("Pin already used for GpioOutput!");
		}
		if (!this.gpiosIn.containsKey(gpio)) {
			Pin pin = this.getPin(gpio);
			if (pin == null) {
				return null;
			}
			this.gpiosIn.put(gpio, this.gpioRactory.provisionDigitalInputPin(pin, gpio));
		}
		return this.gpiosIn.get(gpio);
	}

	private GpioPinDigitalOutput getGpioOutput(String gpio) throws Exception {
		if (this.gpiosIn.containsKey(gpio)) {
			throw new Exception("Pin already used for GpioInput!");
		}
		if (!this.gpiosOut.containsKey(gpio)) {
			Pin pin = this.getPin(gpio);
			if (pin == null) {
				return null;
			}
			this.gpiosOut.put(gpio, this.gpioRactory.provisionDigitalOutputPin(pin, gpio, PinState.LOW));
		}
		return this.gpiosOut.get(gpio);
	}

	private Pin getPin(String gpio) {
		Pin pin = null;
		switch (gpio) {
		case "gpio00":
			pin = RaspiPin.GPIO_00;
			break;
		case "gpio01":
			pin = RaspiPin.GPIO_01;
			break;
		case "gpio02":
			pin = RaspiPin.GPIO_02;
			break;
		case "gpio03":
			pin = RaspiPin.GPIO_03;
			break;
		case "gpio04":
			pin = RaspiPin.GPIO_04;
			break;
		case "gpio05":
			pin = RaspiPin.GPIO_05;
			break;
		case "gpio06":
			pin = RaspiPin.GPIO_06;
			break;
		case "gpio07":
			pin = RaspiPin.GPIO_07;
			break;
		case "gpio08":
			pin = RaspiPin.GPIO_08;
			break;
		case "gpio09":
			pin = RaspiPin.GPIO_09;
			break;
		case "gpio10":
			pin = RaspiPin.GPIO_10;
			break;
		case "gpio11":
			pin = RaspiPin.GPIO_11;
			break;
		case "gpio12":
			pin = RaspiPin.GPIO_12;
			break;
		case "gpio13":
			pin = RaspiPin.GPIO_13;
			break;
		case "gpio14":
			pin = RaspiPin.GPIO_14;
			break;
		case "gpio15":
			pin = RaspiPin.GPIO_15;
			break;
		case "gpio16":
			pin = RaspiPin.GPIO_16;
			break;
		case "gpio17":
			pin = RaspiPin.GPIO_17;
			break;
		case "gpio18":
			pin = RaspiPin.GPIO_18;
			break;
		case "gpio19":
			pin = RaspiPin.GPIO_19;
			break;
		default:
			pin = null;
		}
		return pin;
	}

}
